package com.un.ebs.context.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.context.domain.SysObject;
import com.un.ebs.context.mapper.DbQueryMapper;
import com.un.ebs.context.mapper.SysObjectMapper;
import com.un.ebs.context.service.SystemDbService;
import com.un.ebs.core.enums.DataTypeEnum;
import com.un.ebs.core.enums.RequestArgEnum;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.metadata.*;
import com.un.ebs.core.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author liubo
 * @email liubocs@163.com
 * @date 2020/6/4 10:21
 */
@Deprecated
@Service
public class SystemDbServiceImpl extends ServiceImpl<SysObjectMapper, SysObject> implements SystemDbService, ServiceExt {

    @Autowired
    private DbQueryMapper dbQueryMapper;

    @Override
    public List<SysObject> queryObject(String objName) {
        LambdaQueryWrapper<SysObject> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(objName)) {
            lq.eq(SysObject::getObjName, objName);
        }
        return baseMapper.selectList(lq);
    }

    public List<MetadataField> buildResponse(String objName) {
        List<MetadataField> ret = new ArrayList<>();

        ret.add(new MetadataField("code", DataTypeEnum.INT));

        MetadataField data = new MetadataField("data", DataTypeEnum.OBJECT);
        data.setIsArray(1);
        data.setChildField(new ArrayList<>());
        for (SysObject col : queryObject(objName)) {
            MetadataField f = new MetadataField();
            f.setName(col.getColName());
            f.setDataType(convetType(col.getDataType()));
            f.setIsArray(0);
            f.setDisplayName(StringUtils.isNullOrEmpty(col.getColDesc()) ? col.getColName() : col.getColDesc());
            data.getChildField().add(f);
        }
        ret.add(data);

        ret.add(new MetadataField("message", DataTypeEnum.STRING));
        return ret;
    }

    public List<RequestArg> buildRequest(String objName) {
        List<RequestArg> ret = new ArrayList<>();
        List<SysObject> argList = queryObject(objName).stream().filter(s -> s.getColName().contains("@")).collect(Collectors.toList());
        if (StringUtils.isNullOrEmpty(argList)) {
            argList = queryObject(objName);
        }
        for (SysObject col : argList) {
            RequestArg f = new RequestArg();
            f.setName(col.getColName());
            f.setDataType(convetType(col.getDataType()));
            f.setIsArray(0);
            f.setDisplayName(StringUtils.isNullOrEmpty(col.getColDesc()) ? col.getColName() : col.getColDesc());
            f.setRequestType(RequestArgEnum.RequestParam);
//            switch (convetType(col.getDataType())){
//                case RESOURCE_DATA:
//            }
            ret.add(f);
        }
        return ret;
    }

    @Override
    public FunctionInfo buildFunction(String objName) {
        List<RequestMethod> methods = new ArrayList<>();
        methods.add(RequestMethod.POST);
        FunctionInfo ret = new FunctionInfo();
        ret.setName("query");
        ret.setUrl("context/query/" + objName);
        ret.setMethod(methods);
        ret.setDescription(objName);
        ret.setRequest(buildRequest(objName));
        ret.setResponse(buildResponse(objName));
        return ret;
    }

    @Override
    public List<FunctionInfo> queryFunctions(String objName) {
        List<FunctionInfo> ret = new ArrayList<>();
        ret.add(buildFunction(objName));
        return ret;
    }

    @Override
    public List<ServiceInfo> queryServices() {
        List<ServiceInfo> ret = new ArrayList<>();
//        System.out.println("........");
//        System.out.println(this.getClass().getName());
//        System.out.println("........");
//        List<String> list = queryObject(null).stream().filter(s -> s.getObjType().trim().equals("V") || s.getObjType().trim().equals("IF")).map(s -> s.getObjName()).distinct().collect(Collectors.toList());
//        for (String name : list) {
//            ServiceInfo s = new ServiceInfo();
//            s.setName(name);
//            s.setUrl("context");
//            s.setIsDynamic(true);
//            //s.setFunctions(queryFunctions(name));
//            ret.add(s);
//        }
        return ret;
    }

    @Override
    public IPage<LinkedHashMap<String, Object>> execQuery(String objName, String sortName, Map<String, Object> args, int pageIndex, int pageSize) {
        List<FunctionInfo> funs = queryFunctions(objName);
        if (StringUtils.isNullOrEmpty(funs)) {
            throw new BusinessException(objName + " 对象没有找到。");
        }

        StringBuilder sbWhere = new StringBuilder();
        for (FunctionInfo item : funs) {
            if (args == null) {
                continue;
            }
            for (RequestArg arg : item.getRequest()) {
                if (args.get(arg.getName()) != null) {
                    switch (arg.getDataType()) {
                        case NUMBER:
                        case INT:
                        case MONEY:
                        case BOOLEAN:
                            sbWhere.append(String.format(" and %s = %d ", arg.getName(), args.get(arg.getName())));
                            break;
                        case STRING:
                        case DATE:
                        case DATETIME:
                        default:
                            sbWhere.append(String.format(" and %s like '%%%s%%' ", arg.getName(), args.get(arg.getName())));
                            break;
                    }
                }
            }
        }

        if (StringUtils.isNullOrEmpty(sortName)) {
            sortName = "current_timestamp";
        }


        StringBuilder sql = new StringBuilder();
        sql.append(String.format("with selectTemp as (select top 100 percent row_number() over (order by %s) as __row_number__ , * from %s where 1=1 %s) select * from selectTemp WHERE __row_number__ BETWEEN %d AND %d ORDER BY __row_number__", sortName, objName, sbWhere.toString(), pageIndex, pageSize));
        List<LinkedHashMap<String, Object>> ret = dbQueryMapper.execSql(sql.toString());

        StringBuilder sqlCount = new StringBuilder();
        sqlCount.append(String.format("select count(1) from %s where 1=1 %s", objName, sbWhere.toString()));

        System.out.println(sql);

        Page page = new Page(pageIndex, pageSize);
        page.setRecords(dbQueryMapper.execSql(sql.toString()));
        page.setTotal(dbQueryMapper.execCount(sqlCount.toString()));
        page.setPages(page.getTotal() / pageSize);

        return page;
    }

    @Override
    public IPage<LinkedHashMap<String, Object>> execQuery(String objName, String sortName, String args, int pageIndex, int pageSize) {
        List<FunctionInfo> funs = queryFunctions(objName);
        if (StringUtils.isNullOrEmpty(funs)) {
            throw new BusinessException(objName + " 对象没有找到。");
        }

        StringBuilder sbWhere = new StringBuilder();

        if (!args.equals("{}")) {
            for (FunctionInfo item : funs) {
                if (args == null) {
                    continue;
                }
                if (!StringUtils.isNullOrEmpty(args)) {
                    sbWhere.append(args);
                }
            }
        }

        if (StringUtils.isNullOrEmpty(sortName)) {
            sortName = "current_timestamp";
        }

        StringBuilder sql = new StringBuilder();
        sql.append(String.format("with selectTemp as (select top 100 percent row_number() over (order by %s) as __row_number__ , * from %s where 1=1 %s) select * from selectTemp WHERE __row_number__ BETWEEN %d AND %d ORDER BY __row_number__", sortName, objName, sbWhere.toString(), pageIndex, pageSize));
        List<LinkedHashMap<String, Object>> ret = dbQueryMapper.execSql(sql.toString());

        StringBuilder sqlCount = new StringBuilder();
        sqlCount.append(String.format("select count(1) from %s where 1=1 %s", objName, sbWhere.toString()));

        System.out.println(sql);

        Page page = new Page(pageIndex, pageSize);
        page.setRecords(dbQueryMapper.execSql(sql.toString()));
        page.setTotal(dbQueryMapper.execCount(sqlCount.toString()));
        page.setPages(page.getTotal() / pageSize);

        return page;
    }

    private DataTypeEnum convetType(String type) {
        switch (type) {
            case "smallint":
            case "bigint":
            case "tinyint":
            case "int":
                return DataTypeEnum.INT;
            case "numeric":
            case "real":
            case "float":
            case "decimal":
                return DataTypeEnum.NUMBER;
            case "date":
                return DataTypeEnum.DATE;
            case "time":
            case "datetime":
            case "datetime2":
                return DataTypeEnum.DATETIME;
            case "bit":
                return DataTypeEnum.BOOLEAN;
            case "nvarchar":
            case "varchar":
            case "char":
            default:
                return DataTypeEnum.STRING;
        }
    }

}
